package me.lubinn.Incantatio;

//import com.platymuus.bukkit.permissions.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import java.util.logging.Logger;

import net.minecraft.server.EntityLiving;
import net.minecraft.server.EntityTNTPrimed;
import net.minecraft.server.MovingObjectPosition;
import net.minecraft.server.WorldServer;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.entity.*;
import org.bukkit.event.player.PlayerChatEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.util.Vector;
import org.bukkit.util.config.Configuration;

import java.util.HashMap;
import java.util.List;
import java.util.Random;
import java.util.Map;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.entity.CraftEntity;
import org.bukkit.event.entity.EntityTargetEvent;
import net.minecraft.server.EntityFireball;
import net.minecraft.server.Vec3D;
import org.bukkit.craftbukkit.entity.CraftArrow;
import org.bukkit.craftbukkit.entity.CraftLivingEntity;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Explosive;
import org.bukkit.entity.Projectile;
import org.bukkit.event.entity.*;
import org.bukkit.plugin.PluginManager;

import me.lubinn.Incantatio.Spells.*;

 // Referenced classes of package me.orion.Incantatio:
//            Incantatio, IncantatioPlayerListener

public class IncantatioSpell
{

    private int size;
    public int n;
    public boolean book_augment;
    public Configuration config;
    public String components[];
    public PlayerChatEvent ev;
    public static IncantatioPlayerListener plugin;
    public static Random rand = new Random();
    
//    private String _LowSecurityComponents[] =
//    	{ "vitrea", "ignis", "aquae", "glacies", "aranea", "folia", "aeris", "cactus",
//    	  "lapis", "obsidianus", "ferrum", "aurum", "adamas", "arena", "fimus" };
//    private String _HighSecurityComponents[] =
//    	{ "vitrea", "aquae", "glacies", "folia", "lapis", "ferrum", "aurum", "adamas",
//    	  "fimus" };
    
    private String listOfSpells[] =
    	{ "accendit", "annulus", "arbore", "bulla", "chasma tempestas", "concalesco", "cubus", "demis", "discus", "domus",
    		"evanescere", "extinguere", "frigidus", "fulmen", "globus ignis", "gradi", "hadoken", "ignis perpetua",
    		"implete aquas", "libyes", "lucem", "lux", "murus", "mutatio", "noctem", "pluvia", "praemium", "remedium",
    		"respiro", "sagitto", "sagitto pluvia", "salio", "sereno", "sphaera", "tempestas", "tholus", "turris",
    		"uanescere", "urgeo", "vello", "vorto",
    		"chunkus erasus", "chunkus renero", };
    
	public static final Map<String, Material> listOfMaterials = new HashMap<String, Material>();
	static
	{
		listOfMaterials.put("fimus", Material.DIRT);
		listOfMaterials.put("aquae", Material.STATIONARY_WATER);
		listOfMaterials.put("aeris", Material.AIR);
		listOfMaterials.put("vitrea", Material.GLASS);
		listOfMaterials.put("glacies", Material.ICE);
		listOfMaterials.put("aranea", Material.WEB);
		listOfMaterials.put("folia", Material.LEAVES);
		listOfMaterials.put("ignis", Material.FIRE);
		listOfMaterials.put("silice", Material.LAVA);
		listOfMaterials.put("lapis", Material.STONE);
		listOfMaterials.put("obsidianus", Material.OBSIDIAN);
		listOfMaterials.put("ferrum", Material.IRON_BLOCK);
		listOfMaterials.put("aurum", Material.GOLD_BLOCK);
		listOfMaterials.put("adamas", Material.DIAMOND_BLOCK);
		listOfMaterials.put("arena", Material.SAND);
		listOfMaterials.put("herba", Material.GRASS);
		
		listOfMaterials.put("explodium", Material.TNT);
	}

    Thread runner;

    public IncantatioSpell(IncantatioPlayerListener instance)
    {
        size = 1;
        n = 0;
        book_augment = false;
        config = null;
        plugin = instance;
    }
    
    private boolean isIn(String list[], String str) //returns true if str is in list
    {
    	for (int i = 0; i < list.length; i++)
    		if (list[i].equalsIgnoreCase(str))
    			return true;
    	return false;
    }

    public void CastSpell(String components[], PlayerChatEvent ev)
    {
        config = Incantatio.config;
        this.components = components;
        this.ev = ev;
        n = 0;
        size = 2;
        book_augment = false;
        
        String spellName = "";
        Spell toCast = null;
        Material material = null; //TODO: remember lastMaterial
        Map<String, Boolean> augments = new HashMap<String, Boolean>();
        
        //ignore case on everything
        for (int i = 0; i < components.length; i++)
        	components[i] = components[i].toLowerCase();
        
        for (int i = 0; i < components.length; i++)
        {
        	//try and get the spell name
        	if (spellName.equals("") || spellName.equals("bulla"))
        	{
        		String foundSpell = "";
        		
        		if (Spell.GetSpell(components[i]) != null)
        			foundSpell = components[i];
	        	if (i < components.length-1)
	        	{
	    			String twoWords = components[i]+" "+components[i+1];
	        		if (Spell.GetSpell(twoWords) != null)
	        		{
	        			foundSpell = twoWords;
	        			i++; //skip next word; it's included in the spell name
	        		}
	        	}

	        	if (!foundSpell.equals(""))
	        	{
	        		if (spellName.equals("bulla"))
	        			augments.put("bubble", true);
	        		spellName = foundSpell;
	        		toCast = Spell.GetSpell(spellName);
	        		Incantatio.log.info("Spell name: "+spellName);
	        		continue;
	        	}
        	}
        	
        	//try and get size-changing words
        	if (size == 2)
        	{
		        if (components[i].equalsIgnoreCase("ultima") && Incantatio.config.getBoolean((new StringBuilder(String.valueOf("world_maiming"))).append("_enabled").toString(), true))
		        	size = 9;
		        else if (components[i].equalsIgnoreCase("supera") && Incantatio.config.getBoolean((new StringBuilder(String.valueOf("world_maiming"))).append("_enabled").toString(), true))
		        	size = 6;
		        else if (components[i].equalsIgnoreCase("magna"))
		            size = 4;
		        else if (components[i].equalsIgnoreCase("parva"))
		            size = 1;
		        else if (components[i].equalsIgnoreCase("infera"))
		        	size = 0;
		        
		        if (size != 2)
		        {
                    //Incantatio.log.info("Size: "+String.valueOf(size));
		        	continue;
		        }
        	}
        	
        	//try and get the material
        	if (material == null)
        	{
        		if (listOfMaterials.containsKey(components[i]))
        		{
        			material = listOfMaterials.get(components[i]);
        			Incantatio.log.info("Material: "+components[i]);
        			continue;
        		}
        	}
        	
        	if (components[i].equalsIgnoreCase("augere") && i+1 < components.length)
        	{
	        	if (components[i+1].equalsIgnoreCase("vi"))
	        		augments.put("force", true);
	        	else if (components[i+1].equalsIgnoreCase("volo"))
	        		augments.put("flight", true);
	        	else if (components[i+1].equalsIgnoreCase("motor"))
	        		augments.put("motion", true);
	        	else if (components[i+1].equalsIgnoreCase("silentium"))
	        		augments.put("silence", true);
        	}
        	if (components[i].equalsIgnoreCase("bulla"))
        		augments.put("bubble", true);
        }
        
        if (!spellName.equals(""))
        {
        	boolean canCast = true;
        	
        	//check for book augment/requirement
            if(Incantatio.config.getBoolean((new StringBuilder(String.valueOf(spellName))).append("_consumes_book").toString(), false))
            {
                if (!PlayerSpendReagent(ev.getPlayer(), Material.BOOK, 1))
                	canCast = false;
            }
            if(Incantatio.config.getBoolean((new StringBuilder(String.valueOf(spellName))).append("_book_augment").toString(), false))
            {
                if (PlayerSpendReagent(ev.getPlayer(), Material.BOOK, 1))
                	augments.put("book", true);
            }

            if (toCast != null && canCast)
        		toCast.CastSpell(ev, material, size, augments);

            if (augments.containsKey("silence"))
            	ev.setCancelled(true);
        }
    }
    
    private void ChunkusErasus(String components[], PlayerChatEvent ev)
    {
        Player player = ev.getPlayer();
        World world = player.getWorld();
    	Location location = ev.getPlayer().getTargetBlock(null, 500).getLocation();
    	Chunk chunk = world.getChunkAt(location);
    	for (int y = 0; y < 128; y++)
    		for (int x = 0; x < 16; x++)
    			for (int z = 0; z < 16; z++)
    				chunk.getBlock(x, y, z).setType(Material.AIR);
    }
    private void ChunkusRenero(String comonents[], PlayerChatEvent ev)
    {
        Player player = ev.getPlayer();
        World world = player.getWorld();
    	Location location = ev.getPlayer().getTargetBlock(null, 500).getLocation();
    	Chunk chunk = world.getChunkAt(location);
    	world.regenerateChunk(chunk.getX(), chunk.getZ());
    }

    private void IgnisSpiritus(String as[], PlayerChatEvent playerchatevent)
    {
    }
    
    private void Sagitto(String components[], PlayerChatEvent ev)
    {
        Player player = ev.getPlayer();
        World world = player.getWorld();
        Vector dir = ev.getPlayer().getEyeLocation().getDirection().normalize();
        Vector pos = player.getEyeLocation().toVector().add(dir);
        for (int i = 0; i < size*size/2 + 1; i++)
        {
        	Arrow a = world.spawnArrow(pos.toLocation(world), dir.multiply(50f), 600f, 10f+2.5f*size);
        	a.teleport(pos.toLocation(world));
        }
    }
    private void SagittoPluvia(String components[], PlayerChatEvent ev)
    {
    	Location location = ev.getPlayer().getTargetBlock(null, 500).getLocation();
    	location.setY(120);
    	for (int i = 0; i < size*size*size*0.15 + size*size*5 + 8; i++)
    	{
    		Arrow a = ev.getPlayer().getWorld().spawnArrow(location, new Vector(0, -10, 0), 600f, 10f+5f*size);
    		double x = rand.nextGaussian() * (0.5+0.15*size);
    		double z = rand.nextGaussian() * (0.5+0.15*size);
    		a.setVelocity(new Vector(x, -10, z));
    		a.teleport(location);
    	}
    }
    
    boolean CheckPermissions(String spell, String components[])
    {
        if(Incantatio.config.getBoolean((new StringBuilder(String.valueOf(spell))).append("_consumes_book").toString(), false))
        {
            return PlayerSpendReagent(ev.getPlayer(), Material.BOOK, 1);
        }
        if(Incantatio.config.getBoolean((new StringBuilder(String.valueOf(spell))).append("_book_augment").toString(), false))
        {
            book_augment = PlayerSpendReagent(ev.getPlayer(), Material.BOOK, 1);
        }
    	return true;
    }
    boolean Hold_place(String spell, String components[]) //FIXME: re-enable permissions!! 
    {
        if(!Incantatio.config.getBoolean((new StringBuilder(String.valueOf(spell))).append("_enabled").toString(), true))
        {
            return false;
        }
        if(Incantatio.config.getBoolean((new StringBuilder(String.valueOf(spell))).append("_enabled").toString(), true) && spell == "celeritas")
        {
            return true;
        }
        if(Incantatio.config.getBoolean("all_spells_require_book", false) && ev.getPlayer().getItemInHand().getType() != Material.BOOK)
        {
            return false;
        }
        if(Incantatio.config.getBoolean((new StringBuilder(String.valueOf(spell))).append("_consumes_book").toString(), false))
        {
            return PlayerSpendReagent(ev.getPlayer(), Material.BOOK, 1);
        }
        
        //DISABLING PERMISSIONS
     /*   if(Incantatio.Permissions != null && !Incantatio.Permissions.has(ev.getPlayer(), (new StringBuilder(String.valueOf(spell))).append(".allow").toString()))
        {
            Incantatio.log.info("Spell not allowed by user.");
            return false;
        }
        */
        
        if(!Incantatio.config.getBoolean((new StringBuilder(String.valueOf(spell))).append("_magna_parva").toString(), false))
        {
            size = 2;
        }
        if(Incantatio.config.getBoolean((new StringBuilder(String.valueOf(spell))).append("_book_augment").toString(), false))
        {
            book_augment = PlayerSpendReagent(ev.getPlayer(), Material.BOOK, 1);
        }
        return true;
    }

    private void Remedium(String components[], PlayerChatEvent ev)
    {
        Player player = ev.getPlayer();
        int health = player.getHealth();
        if(book_augment)
        {
            player.setHealth(20);
        } else
        if(health + 6 < 20)
        {
            health += 6;
            player.setHealth(health);
        } else
        {
            health = 20;
            player.setHealth(health);
        }
    }

    private void Vello(String components[], PlayerChatEvent ev)
    {
        Location location = ((Block)ev.getPlayer().getLastTwoTargetBlocks(null, 500).get(0)).getLocation();
        Vector vector = ev.getPlayer().getEyeLocation().getDirection();
        List<Entity> entities = ev.getPlayer().getWorld().getEntities();
        for(Iterator<Entity> iterator = entities.iterator(); iterator.hasNext();)
        {
            Entity entity = iterator.next();
            if(location.distance(entity.getLocation()) <= 5D && (Incantatio.config.getBoolean("vello_affects_players", true) || !(entity instanceof Player)) && (Incantatio.config.getBoolean("vello_affects_self", true) || ev.getPlayer().getEntityId() != entity.getEntityId()))
            {
                entity.setVelocity(vector.multiply(-(1D+size)));
            }
        }

    }

    private void Urgeo(String components[], PlayerChatEvent ev)
    {
        String spell = "urgeo";
        Location location = ((Block)ev.getPlayer().getLastTwoTargetBlocks(null, 500).get(0)).getLocation();
        Vector vector = ev.getPlayer().getEyeLocation().getDirection();
        List<Entity> entities = ev.getPlayer().getWorld().getEntities();
        for(Iterator<Entity> iterator = entities.iterator(); iterator.hasNext();)
        {
            Entity entity = iterator.next();
            if(location.distance(entity.getLocation()) <= 5D && (Incantatio.config.getBoolean((new StringBuilder(String.valueOf(spell))).append("_affects_players").toString(), true) || !(entity instanceof Player)) && (Incantatio.config.getBoolean((new StringBuilder(String.valueOf(spell))).append("_affects_self").toString(), true) || ev.getPlayer().getEntityId() != entity.getEntityId()))
            {
                entity.setVelocity(vector.multiply(1D+size));
            }
        }

    }

    private void Mutatio(String components[], PlayerChatEvent ev)
    {
        Location location = ev.getPlayer().getTargetBlock(null, 500).getLocation();
        World world = ev.getPlayer().getWorld();
        List<Entity> entities = world.getEntities();
        for(Iterator<Entity> iterator = entities.iterator(); iterator.hasNext();)
        {
            Entity entity = iterator.next();
            Location oloc = entity.getLocation();
            if(location.distance(oloc) <= 5D && ((entity instanceof Creeper) || (entity instanceof Zombie) || (entity instanceof Skeleton) || (entity instanceof Spider)))
            {
                Location eloc = entity.getLocation();
                if(eloc.getBlock().getType() == Material.WATER || eloc.getBlock().getType() == Material.STATIONARY_WATER)
                {
                    CreatureType creatures[] = {
                        CreatureType.CHICKEN, CreatureType.COW, CreatureType.SHEEP, CreatureType.SQUID
                    };
                    entity.remove();
                    world.playEffect(eloc, Effect.SMOKE, 1);
                    int i = (int)(Math.random() * (double)creatures.length);
                    CreatureType creature = creatures[i];
                    world.spawnCreature(eloc, creature);
                } else
                {
                    CreatureType creatures[] = {
                        CreatureType.CHICKEN, CreatureType.COW, CreatureType.SHEEP
                    };
                    entity.remove();
                    world.playEffect(eloc, Effect.SMOKE, 1);
                    int i = (int)(Math.random() * (double)creatures.length);
                    CreatureType creature = creatures[i];
                    world.spawnCreature(eloc, creature);
                }
            }
        }

    }

    private boolean IsForceful(String components[], PlayerChatEvent ev2)
    {
    	int l = components.length;
    	if (l < 2) return false;
        return components[l - 2].equalsIgnoreCase("augere") && components[l - 1].equalsIgnoreCase("vi");
    }

    private void IsSilent(String components[], PlayerChatEvent ev2, int i)
    {
    	int l = components.length;
        if (l < 2) return;
        if(components[l - 2].equalsIgnoreCase("augere") && components[l - 1].equalsIgnoreCase("silentium"))
            ev2.setCancelled(true);
    }
    
    private boolean IsMotion(String components[], PlayerChatEvent ev)
    {
    	int l = components.length;
    	if (l < 2) return false;
        return components[l - 2].equalsIgnoreCase("augere") && components[l - 1].equalsIgnoreCase("motor");
    }
    
    private boolean IsFlying(String components[], PlayerChatEvent ev)
    {
    	int l = components.length;
    	if (l < 2) return false;
        return components[l - 2].equalsIgnoreCase("augere") && components[l - 1].equalsIgnoreCase("volo");
    }

    public boolean PlayerSpendReagent(Player player, Material reagent, int count)
    {
        PlayerInventory inventory = player.getInventory();
        int slot = inventory.getHeldItemSlot();
        ItemStack item = player.getItemInHand();
        int amount = item.getAmount();
        Material typeid = item.getType();
        if(typeid != reagent)
        {
            return false;
        }
        if(amount > count)
        {
            item.setAmount(amount - count);
            return true;
        }
        if(amount < count)
        {
            return false;
        }
        if(amount == count)
        {
            inventory.clear(slot);
            return true;
        } else
        {
            return false;
        }
    }

    private void Extinguere(String components[], PlayerChatEvent ev)
    {
        if(ev.getPlayer().getFireTicks() > 0)
        {
            ev.getPlayer().getWorld().playEffect(ev.getPlayer().getLocation(), Effect.SMOKE, 1);
        }
        ev.getPlayer().setFireTicks(0);
    }

    private void ImpleteAquas(String components[], PlayerChatEvent ev)
    {
        int radius = 6 + 4*size;
        Block block = ev.getPlayer().getTargetBlock(null, 500);
        Location origin = block.getLocation();
        int xorg = (int)origin.getX();
        int yorg = (int)origin.getY();
        int zorg = (int)origin.getZ();
        if(Math.abs(yorg - 63) < radius)
        {
            int y = 63;
            for(int x = xorg - radius - 1; x <= xorg + radius + 1; x++)
            {
                for(int z = zorg - radius - 1; z <= zorg + radius + 1; z++)
                {
                    int dx = x - xorg;
                    int dz = z - zorg;
                    if((int)Math.sqrt(dx * dx + dz * dz) <= radius)
                    {
                        Block targetblock = ev.getPlayer().getWorld().getBlockAt(x, y, z);
                        Material type = targetblock.getType();
                        if(type == Material.AIR || type == Material.WATER || type == Material.STATIONARY_WATER)
                        {
                            targetblock.setType(Material.STATIONARY_WATER);
                            //targetblock.getWorld().playEffect(targetblock.getLocation(), Effect.SMOKE, 1);
                        }
                    }
                }

            }

        }
    }


    private Material GetMaterial(String latinname)
    {
        if(latinname.equalsIgnoreCase("aquae"))
            return Material.STATIONARY_WATER;
        if(latinname.equalsIgnoreCase("aeris"))
            return Material.AIR;
        if(latinname.equalsIgnoreCase("vitrea"))
            return Material.GLASS;
        if(latinname.equalsIgnoreCase("glacies"))
            return Material.ICE;
        if(latinname.equalsIgnoreCase("aranea"))
            return Material.WEB;
        if(latinname.equalsIgnoreCase("folia"))
            return Material.LEAVES;
        if(latinname.equalsIgnoreCase("ignis"))
            return Material.FIRE;
        if(latinname.equalsIgnoreCase("silice"))
            return Material.LAVA;
        if(latinname.equalsIgnoreCase("cactus"))
        	return Material.CACTUS;
        if(latinname.equalsIgnoreCase("lapis"))
        	return Material.STONE;
        if(latinname.equalsIgnoreCase("obsidianus"))
        	return Material.OBSIDIAN;
        if(latinname.equalsIgnoreCase("ferrum"))
        	return Material.IRON_BLOCK;
        if(latinname.equalsIgnoreCase("aurum"))
        	return Material.GOLD_BLOCK;
        if(latinname.equalsIgnoreCase("adamas"))
        	return Material.DIAMOND_BLOCK;
        if(latinname.equalsIgnoreCase("arena"))
        	return Material.SAND;
        if(latinname.equalsIgnoreCase("fimus"))
        	return Material.DIRT;
        if(latinname.equalsIgnoreCase("herba"))
        	return Material.GRASS;
        return null;
    }



    private void IgnisPerpetua(String components[], PlayerChatEvent ev)
    {
        int w = 1;
        if(!Incantatio.config.getBoolean("ignis_perpetua_replaces_block", false))
        {
            w = 0;
        }
        Block block = (Block)ev.getPlayer().getLastTwoTargetBlocks(null, 500).get(w);
        Block aboveblock = block.getFace(BlockFace.UP);
        Material type = block.getType();
        Material abovetype = aboveblock.getType();
        if(type != Material.BEDROCK && abovetype != Material.BEDROCK)
        {
            block.setType(Material.NETHERRACK);
            block.getWorld().playEffect(block.getLocation(), Effect.SMOKE, 1);
            aboveblock.setType(Material.FIRE);
            aboveblock.getWorld().playEffect(aboveblock.getLocation(), Effect.SMOKE, 1);
        }
    }


    private void Murus(String components[], PlayerChatEvent ev)
    {
        //String spell = "murus";
        //if(Arrays.asList(_MurusAllowedComponents).contains(components[n + 1]) && Incantatio.config.getBoolean((new StringBuilder(String.valueOf(spell))).append("_").append(components[n + 1]).toString(), false))
        {
            boolean overwrite = IsForceful(components, ev);
            Material component = GetMaterial(components[n + 1]);
            int length = 5 + 15*size/2;
            Vector vector = ev.getPlayer().getEyeLocation().getDirection().normalize();
            Location location;
            if (IsFlying(components, ev))
            	location = ev.getPlayer().getTargetBlock(null, 10 + 5*size).getLocation();
            else
            	location = ev.getPlayer().getTargetBlock(null, 500).getLocation();
            int xorg = location.getBlockX();
            int yorg = location.getBlockY();
            int zorg = location.getBlockZ();
            double vx = vector.getX();
            double vz = vector.getZ();
            double ox = -vz;
            double oz = vx;
            for(int i = -length / 2; i <= length / 2 + 1; i++)
            {
                location.setX((double)xorg + (double)i * ox);
                location.setZ((double)zorg + (double)i * oz);
                for(int y = Math.max(yorg, 1); y <= Math.min(yorg + length/2, 120); y++)
                {
                    location.setY(y);
                    Block block = location.getBlock();
                    Material type = block.getType();
                    if(overwrite && type != Material.BEDROCK)
                    {
                        block.setType(component);
                        //block.getWorld().playEffect(block.getLocation(), Effect.SMOKE, 1);
                    } else
                    if(type == Material.AIR)
                    {
                        block.setType(component);
                        //block.getWorld().playEffect(block.getLocation(), Effect.SMOKE, 1);
                    }
                }

            }
            if (IsMotion(components, ev))
            	ev.getPlayer().teleport(new Vector(xorg, yorg+length/2+1, zorg).toLocation(ev.getPlayer().getWorld()));
        }
    }

    
    
    // NEW SPELLS RAWR OMG
    // fireball    
    private void GlobusIgnis(String components[], PlayerChatEvent ev)
    {
    		CraftWorld world = (CraftWorld)ev.getPlayer().getWorld();
    	
    		CraftPlayer craftPlayer = (CraftPlayer) ev.getPlayer();
			EntityLiving playerEntity = craftPlayer.getHandle();
    	 	
    	 
    	 	// Start it off a bit away from the player
    	 	double distance = 4+0.5*size;
    		
    	 
    	 	for (int i = 0; i < (int)(1.25*size*size) + 1; i++)
            {
            	Location location = ev.getPlayer().getLocation();
        		Vector aim = ev.getPlayer().getEyeLocation().getDirection().normalize();
    	 		
    	 		location.setX(location.getX() + aim.getX() * distance);
        	 	location.setY(location.getY() + (2.0) + 0.5);
        	 	location.setZ(location.getZ() + aim.getZ() * distance);
    	 		
            	Vector r = Vector.getRandom().subtract(new Vector(0.5, 0.5, 0.5)).normalize().multiply(2+0.5*size);
            	Vector v = location.toVector().add(r);
            	
        		
            	EntityFireball fireball = new EntityFireball(((CraftWorld) craftPlayer.getWorld()).getHandle(), playerEntity, aim.getX(),aim.getY(),aim.getZ());
            	
            	fireball.setDirection(aim.getX(), aim.getY(), aim.getZ());
            	
            	fireball.locX = v.getX();
            	fireball.locY = v.getY();
            	fireball.locZ = v.getZ();
            	
//            	fireball.motX = aim.getX() * .1;
//        	 	fireball.motY = aim.getY() * .1;
//        	 	fireball.motZ = aim.getZ() * .1;
            	
            	((CraftWorld) craftPlayer.getWorld()).getHandle().addEntity(fireball);
            	
            }
    	 	
    	 	
        
    }
    
    //HADOKEN
    private void Hadoken(String components[], PlayerChatEvent ev)
    {
    	CraftWorld world = (CraftWorld)ev.getPlayer().getWorld();
    	Location location = ev.getPlayer().getLocation();
    	Vector aim = ev.getPlayer().getEyeLocation().getDirection().normalize();
    	
    	location.setX(location.getX() + aim.getX() * 4.0);
	 	location.setY(location.getY() + 0.5);
	 	location.setZ(location.getZ() + aim.getZ() * 4.0);
    	
    	for (int i = 0; i < 100; i++)
    	{
    		CraftArrow a = (CraftArrow) ev.getPlayer().getWorld().spawnArrow(location, aim, 600f, 10f+5f*size);
    		a.setVelocity(aim.normalize().multiply(10F));
    		world.getHandle().addEntity(a.getHandle());
    	}
    }
   
    
    //Rotate
    //AWESOME ENVIRONMENT WARP
    //Rename to 
    
    
      // VERY USEFUL SHIT: 
      // Durations framework
      
      
      //K, so, in theory, all you need to do is throw down a while loop over this boolean until its false
      //FUUUUUUUUUUUUUUUCK
      // NEVERMIND
      //BAD ME
      // NOTE: Will an action listener fuck with everything?
//      new Timer(delay, taskPerformer).start();
//      
//      int delay = 1000; //milliseconds
//      ActionListener taskPerformer = new ActionListener() 
//      {
//          public void actionPerformed(ActionEvent evt) 
//          {
//              //...Perform a task...
//          }
//      };
//      
      
       
}
